#pragma once
#include "pch.h"
#include <semaphore>
#include "Common.h"
#include "PointCloudHandler.h"
#include "LocalEdgeCollapseMeshSimplification.h"
#include "MeshReconstruction.h"

namespace AutomatedSurfaceReconstruction
{
	extern std::string OutputPath;
	extern long long  ExpectedMeshNum;
	extern std::counting_semaphore<100> OutputSemaphore;
	extern std::ofstream WriteLogFile;


	class CReconstructMeshFilter :public hiveSystem::CSingleStreamFilter<std::pair<std::pair<std::string, CGALPointSetType>, CGALPointSetType>, 6, std::pair<std::pair<std::string, CGALMeshType>, CGALPointSetType>, 6>
	{
	private:
		void __registerOwnMemberFuncAsDataProcessFuncV() override { registerDataProcessFunc(std::bind(&CReconstructMeshFilter::__reconstructMesh, this, std::placeholders::_1, std::placeholders::_2)); }

		void __reconstructMesh(const std::pair<std::pair<std::string, CGALPointSetType>, CGALPointSetType>& vPointSet2DXFRoad, std::pair<std::pair<std::string, CGALMeshType>, CGALPointSetType>& voMesh2DXFRoad)
		{
			WriteLogFile << generateTime() << "        [" << vPointSet2DXFRoad.first.first << "] start to reconstruct mesh" << std::endl;
			CScaleSpaceMeshReconstruction MeshReconstructor(vPointSet2DXFRoad.first.second);
			CGALMeshType TempCGALMesh = MeshReconstructor.reconstrcut();
			
			voMesh2DXFRoad.first.first = vPointSet2DXFRoad.first.first;
			voMesh2DXFRoad.first.second = std::move(TempCGALMesh);
			voMesh2DXFRoad.second = vPointSet2DXFRoad.second;
			WriteLogFile << generateTime() << "        [" << vPointSet2DXFRoad.first.first << "] finish reconstructing mesh" << std::endl;
		}
	};

	class CSimplifyMeshFilter :public hiveSystem::CSingleStreamFilter<std::pair<std::pair<std::string, CGALMeshType>, CGALPointSetType>, 1, std::pair<std::string,CGALMeshType>, 1>
	{
	private:
		void __registerOwnMemberFuncAsDataProcessFuncV() override { registerDataProcessFunc(std::bind(&CSimplifyMeshFilter::__simplifyMesh, this, std::placeholders::_1, std::placeholders::_2)); }

		void __simplifyMesh(const std::pair<std::pair<std::string, CGALMeshType>, CGALPointSetType>& vMesh2DXFRoad, std::pair<std::string,CGALMeshType>& voMesh)
		{
			
			WriteLogFile << generateTime() << "        [" << vMesh2DXFRoad.first.first << "] start to simplify mesh" << std::endl;
			voMesh.first = vMesh2DXFRoad.first.first;
			CGALMeshType TempCGALMesh = vMesh2DXFRoad.first.second;
			CLocalEdgeCollapseMeshSimplification LocalSimplifier(TempCGALMesh, ExpectedMeshNum);
			LocalSimplifier.simplifyMeshLocally(vMesh2DXFRoad.second);
			voMesh.second = LocalSimplifier.getMesh();
			WriteLogFile << generateTime() << "        [" << vMesh2DXFRoad.first.first << "] finish simplifying mesh" << std::endl;

		}
	};


	class CSaveMesh :public hiveSystem::CSingleStreamFilter<std::pair<std::string,CGALMeshType>, 6, std::string, 6>
	{
	private:
		void __registerOwnMemberFuncAsDataProcessFuncV() override { registerDataProcessFunc(std::bind(&CSaveMesh::__saveMesh, this, std::placeholders::_1, std::placeholders::_2)); }

		void __saveMesh(const std::pair<std::string,CGALMeshType>& vMesh, std::string& voOutputPath)
		{
			
			WriteLogFile << generateTime() << "        [" << vMesh.first << "] start to save mesh" << std::endl;
			size_t FileNameBegin = vMesh.first.find_last_of('/'), FileNameEnd = vMesh.first.find_last_of('.');
			std::string OutputFileName = OutputPath + "_" + vMesh.first.substr(FileNameBegin + 1, FileNameEnd - FileNameBegin - 1) + ".obj";
			std::ofstream OutputStream(OutputFileName, std::ios::out | std::ios::binary);
			CGAL::IO::write_OBJ(OutputStream, vMesh.second, CGAL::parameters::stream_precision(17));
			AutomatedSurfaceReconstruction::OutputSemaphore.release();
			voOutputPath = OutputFileName;
			WriteLogFile << generateTime() << "        [" << vMesh.first << "] finish saving mesh and save as [" << OutputFileName<<"]"<< std::endl;
		}
	};
}